package loadTesting;

import java.io.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;


public class TesterThread implements Runnable
{
    private final int iClientId;
    private final Tester parent;
    private ProcessBuilder pb;
    private volatile BufferedReader brIn;

    
    private PrintWriter out;
    private final List<String> arAuctionList;
    private final Timer timCreator;
 /*   private final Timer timLister;
    private final Timer timBidder;*/
    private Process process;
//    private boolean bStop;
    
    
    public TesterThread(final int iClientid,final Tester parent) throws IOException
    {
        this.parent=parent;
        this.iClientId=iClientid;
        //expected Auctions at same time: duration in minutes * auctions per minute * number of clients 
        arAuctionList=new ArrayList<String>(parent.getiAuctionsDuration()/60 * parent.getiAuctionsPerMinute() * parent.getiClientCount());
        String classpath="\""+System.getProperty("user.dir")+System.getProperty("file.separator")+"build\"";

       // String classpath="\"D:\\Eigene Dateien\\Studium\\12WS-Verteilte Systeme\\Ue2\\template\\build\"";
        //pb=new ProcessBuilder("java","-cp",classpath,"client.ClientMain",parent.getServerHost()+" "+parent.getTcpPort()+" "+1);
        //pb=new ProcessBuilder("java","-cp",classpath,"client.ClientMain",parent.getServerHost(),parent.getTcpPort(),"1");
        System.out.println(new File("ant").getPath());
        System.out.println(new File("java").getPath());
        try
        {
            pb=new ProcessBuilder("ant.exe","run-client1");
            pb.directory(new File(System.getProperty("user.dir")));
            pb.redirectErrorStream(true);
            process=pb.start();
        }catch(Exception ex)
        {
            ex.getCause().printStackTrace();
        }
       
          
        timCreator=new Timer(true);
  /*      timLister=new Timer(true);
        timBidder=new Timer(true);*/
    }
    


    @Override
    public void run() 
    {
        out = new PrintWriter(process.getOutputStream(), true);
        brIn = new BufferedReader(new InputStreamReader(process.getInputStream()));
        
        sendCommandIgnoreAnswer("!login "+iClientId);

        timCreator.scheduleAtFixedRate(new CreatorTask(), 0, 60/parent.getiAuctionsPerMinute()*1000);
        timCreator.scheduleAtFixedRate(new ListerTask(), 0, 60/parent.getiUpdateIntervalSec()*1000);
        timCreator.scheduleAtFixedRate(new BidderTask(), 0, 60/parent.getiBidsPerMinute()*1000);
    /*    timLister.scheduleAtFixedRate(new ListerTask(), 0, parent.getiUpdateIntervalSec()*1000);
        timBidder.scheduleAtFixedRate(new BidderTask(), 0, 60/parent.getiBidsPerMinute()*1000);*/
        
   /*     while(!bStop)
        {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException ex) {
                Logger.getLogger(TesterThread.class.getName()).log(Level.SEVERE, null, ex);
            }
        }*/
        
    }
    
    public void stop()
    {
        sendCommandIgnoreAnswer("!end");
    }
    
    
    public synchronized void sendCommandIgnoreAnswer(final String command)
    {
        try 
        {
            out.println(command);
            do
            {
                //brIn.readLine();
                System.out.println(brIn.readLine());
            }
            while(brIn.ready());
        } catch (IOException ex) {
            Logger.getLogger(TesterThread.class.getName()).log(Level.SEVERE, null, ex);
        }        
    }
    
    public void sendCommandSaveAnswer(final String command)
    {
        try 
        {
            synchronized(arAuctionList)
            {
                arAuctionList.clear();
                synchronized(this)
                {
                    out.println(command);
                    do 
                    {
                        final String strLine = brIn.readLine();
                        if (strLine != null && !strLine.isEmpty() && !strLine.equals("No auctions available!")) 
                        {
                            arAuctionList.add(strLine);
                        }
                    }
                    while (brIn.ready());
                }
            }
        } catch (IOException ex) 
        {
            Logger.getLogger(TesterThread.class.getName()).log(Level.SEVERE, null, ex);
        }   
    }    
    
	private class CreatorTask
	extends TimerTask
	{
		private final String command;
	
		public CreatorTask()
		{
                    super();
                    command="!create "+TesterThread.this.parent.getiAuctionsDuration()+" "+iClientId;
		}
		@Override
		public void run() 
		{
                    sendCommandIgnoreAnswer(command);
                }
	}
        
    private class ListerTask
            extends TimerTask {

        public ListerTask() {
            super();
        }

        @Override
        public void run() 
        {
            sendCommandSaveAnswer("!list");
        }
    }
        
	private class BidderTask
	extends TimerTask
	{
            private final Random randomGenerator;
            private final NumberFormat numberFormat;
            
            public BidderTask()
            {
                super();
                randomGenerator = new Random();
		numberFormat=DecimalFormat.getInstance();
		numberFormat.setMaximumFractionDigits(2);
		numberFormat.setMinimumFractionDigits(2);                
            }
            @Override
            public void run() 
            {
                synchronized(arAuctionList)
                {
                    final int randomId=randomGenerator.nextInt(arAuctionList.size()+1);
                    if(randomId<arAuctionList.size())
                    {
                        final String auction=arAuctionList.get(randomId);
                        try 
                        {
                            int iPointindex;
                            if((iPointindex=auction.indexOf('.'))>0)
                            {
                                final String auctionId=auction.substring(0,auction.indexOf('.')); //auctionid is before the first '.'
                                sendCommandIgnoreAnswer("!bid "+auctionId+" "+numberFormat.format(System.currentTimeMillis()-parent.getTestStart()));
                            }
                         }
                        catch(java.lang.StringIndexOutOfBoundsException ioux)
                        {
                            Logger.getLogger(TesterThread.class.getName()).log(Level.SEVERE, null, ioux);
                        }
                    }
                }
            }
	}            
}
